/*
 * @Author: yangshangchao
 * @Date: 2025-01-23 17:49:39
 * @LastEditors: yangshangchao
 * @Description: 头部注释
 */
// 目标：我们操作父组件的状态改变时，会导致子组件的重新渲染，这个不是必要的过程。所以需要一个Hook优化性能，避免没必要的渲染子组件。
// 问：为什么会导致子组件的重新渲染？
// 首先明确 React 组件的渲染条件：1.组件的 props 发生变化 2.组件的 state 发生变化 3.useContext 发生变化
// 1.API- React.memo的使用
// 2.useMemo 它在每次重新渲染的时候能够缓存(Memoization记忆化)计算的结果。calculateValue通常是进行复杂计算的函数，也就是使用了这个hook，避免了每次渲染都进行复杂的逻辑或者计算。
//   它会返回一个缓存的值，当依赖项发生变化时，才会重新计算并返回新的值。类似Vue的computed
//   语法：useMemo(calculateValue, dependencies)
//   calculateValue：一个函数，返回一个计算好（处理好）的值，
//   dependencies：当依赖项发生变化时，才会重新计算并返回新的值。
// 3.购物车案例。使用useMemo优化性能，计算总计价格。

// 验证案例React.memo的使用 1.输入框输入时，不需要重新渲染子组件  2.点击搜索时，才更新子组件

import { Button, Flex, Input } from 'antd';
import React, { useMemo, useState } from 'react';

interface Props {
  name: string;
}

interface Users {
  name: string;
  age: number;
  email: string;
}

interface UserCardProps {
  user: Users;
}

const Card = React.memo((props: Props) => {
  console.log(props.name, 'Reander子组件');
  return <div>Child</div>;
});

// 技巧：直接在传参解构出 user，定义类型 ({ user }: UserCardProps)
// 对比：如果 (props:UserCardProps)  组件编写状态的时候就要 props.xxx，不太优雅
const UserCard = React.memo(({ user }: UserCardProps) => {
  console.log('Reander-UserCard组件');
  const styles = {
    backgroundColor: 'lightblue',
    padding: '20px',
    borderRadius: '10px',
    margin: '10px',
  };
  return (
    <div style={styles}>
      <h1>{user.name}</h1>
      <p>{user.age}</p>
      <p>{user.email}</p>
    </div>
  );
});

const App = () => {
  const [name, setName] = useState('');
  const [keyword, setKeyword] = useState(''); // 改变keyword时，子组件添加了React.Memo后，不重新渲染子组件。只有点击搜索按钮，改变传递给它的props才重新渲染
  const search = () => {
    setName(keyword);
    setUsers({ ...users, name: keyword });
  };
  const [users, setUsers] = useState<Users>({
    name: '张三',
    age: 18,
    email: 'zhangsan@example.com',
  });

  // 验证2.useMemo
  const [count, setCount] = useState(1);
  const memoizedValue = useMemo(() => {
    console.log('useMemo');
    return count * 2;
  }, [count]); // 触发时机看dependencies

  // 3.购物车案例
  const [goods, setGoods] = useState([
    { id: 1, name: '苹果', price: 10, count: 1 },
    { id: 2, name: '香蕉', price: 20, count: 1 },
    { id: 3, name: '橘子', price: 30, count: 1 },
  ]);
  const changeCount = (payload: { id: number; type: string }) => {
    const { id, type  } = payload
    setGoods(
      goods.map(item => {
        if (item.id === id) {
          if (type === 'increment') {
            return { ...item, count: item.count + 1 }
          }
          return { ...item, count: item.count - 1 }
        }
        return item
      })
    )
  }

  // const total = () => {
  //   console.log('total');
  //   return goods.reduce((pre, item) => {
  //     return pre + item.price * item.count;
  //   }, 0);
  // };

  const total = useMemo(() => {
    console.log('useMemo-total');
    return goods.reduce((pre, item) => {
      return pre + item.price * item.count;
    }, 0);
  }, [goods]);

  return (
    <>
      <Flex>
        <Input value={keyword} onChange={(e) => setKeyword(e.target.value)} />
        <Button type="primary" onClick={search}>
          搜索
        </Button>
      </Flex>
      <Card name={name} />
      <UserCard user={users} />
      {/* useMemo的用法 */}
      <h3>useMemo的简单用法</h3>
      <Button type="primary" onClick={() => setCount(count + 1)}>
        +1
      </Button>
      <div>返回count*2的值:{memoizedValue}</div>
      <h3>useMemo的实际Demo：购物车</h3>
      <table border={1} cellPadding={5} cellSpacing={0}>
        <thead>
          <tr>
            <th>商品</th>
            <th>数量</th>
            <th>价格</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody>
          {goods.map((good, index) => {
            return (
              <tr key={index}>
                <td>{good.name}</td>
                <td>{good.count}</td>
                <td>{good.count * good.price}</td>
                <td>
                  <Button type="primary" onClick={() => { changeCount({id:good.id, type: 'increment'}); }}> +1</Button>
                  <Button type="primary" onClick={() => { changeCount({id:good.id, type: 'decrement'}); }}>-1</Button>
                </td>
              </tr>
            );
          })}
        </tbody>
        {/* 对比不使用 useMemo，改变组件state的值会触发 total函数，没有必要！ */}
        {/* <tfoot><tr><td>总计:</td><td>{ total()}</td></tr></tfoot> */}
        <tfoot>
          <tr>
            <td>总计:</td>
            <td colSpan={3}>{total}</td>
          </tr>
        </tfoot>
      </table>
    </>
  );
};

export default App;
